﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Scribe4net
{
    public class JsonSerializationWriter : ISerializationWriter
    {
        StringBuilder sb = new StringBuilder();
        string _indent = "    ";
        bool _isTopObjectList = false;
        bool _isInList = false;

        public void Start(string objName, bool isList)
        {
            _isTopObjectList = isList;
            if (!isList)
            {
                ++IndentationLevel;
                sb.AppendLine("{");
                WriteIndentation();

                sb.AppendLine("\"" + objName + "\" : ");
            }
        }

        public int IndentationLevel { get; set; }

        private void WriteIndentation()
        {
            for (int i = 0; i < IndentationLevel; ++i)
            {
                sb.Append(_indent);
            }
        }
        public void ListStart(string listObjectName, int dept, bool oneLiner)
        {
            _isInList = true;
            if (sb.Length > 2 && sb[sb.Length - 2] != ':')
                WriteIndentation();

            sb.Append("[");

            if (!oneLiner)
                sb.AppendLine();
        }

        int GetLastIndexOf(char ch)
        {
            for (int i = sb.Length - 1; i >= 0; --i)
            {
                if (sb[i] == ch)
                    return i;
            }
            return -1;
        }
        public void ListEnd(string listObjectName, int dept)
        {
            _isInList = false;
            //bool emptyList = GetLastIndexOf('[') == sb.Length - 1 || GetLastIndexOf('[') == sb.Length - 3 && sb[sb.Length-1]=='\n';
            bool emptyList =
                ((GetLastIndexOf('[') > GetLastIndexOf('\"') && GetLastIndexOf('[') > GetLastIndexOf(']')))
                || sb.ToString(sb.Length - 10, 10).Trim().EndsWith("null");

            //rem ove ',' for last element
            int loc = GetLastIndexOf(',');

            if (!emptyList && loc != -1)
                sb.Remove(loc, 1);

            //if list is empty, there is no need for it to be on a seperate line
            //remove the list opening + indentation and replace it with "[]"
            int colonLoc = GetLastIndexOf(':');
            if (emptyList && colonLoc != -1)
            {
                sb.Remove(colonLoc + 2, sb.Length - colonLoc - 2);
                sb.AppendLine("[]");
                return;
            }

            if (sb[sb.Length - 1] == '\n')
                WriteIndentation();

            sb.AppendLine("]");
        }

        public void ListItemStart(string listItemObjectName, int dept, bool oneLiner)
        {
            if (oneLiner)
                WriteIndentation();
        }

        public void ListItemEnd(string listItemObjectName, int dept, bool oneLiner)
        {
            sb.AppendLine(",");
        }

        public void DictStart(string dictObjectName, int dept, bool oneLiner)
        {
            WriteIndentation();
            sb.AppendLine("{");
        }

        public void DictEnd(string dictObjectName, int dept)
        {
            int loc = GetLastIndexOf(',');
            if (loc != -1)
                sb.Remove(loc, 1);

            WriteIndentation();
            sb.Append("}");
        }

        public void DictItemStart(string dictItemObjectName, int dept, bool oneLiner)
        {
            WriteIndentation();
            sb.Append("\"" + dictItemObjectName + "\" : ");

            if (!oneLiner)
                sb.AppendLine();
        }

        public void DictItemEnd(string dictItemObjectName, int dept)
        {
            if (sb[sb.Length - 1] != '\n')
            {
                sb.AppendLine(",");
            }
            else
            {
                sb.Append(",");
            }
        }

        public void ObjectStart(string objectName, int dept, bool oneLiner)
        {
            WriteIndentation();
            sb.AppendLine("{");
        }

        public void ObjectEnd(string objectName, int dept)
        {
            //if (!sb.ToString(sb.Length-10,10).Trim().EndsWith("null"))

            int loc = GetLastIndexOf(',');
            if (loc != -1)
                sb.Remove(loc, 1);

            WriteIndentation();
            sb.Append("}");
        }

        public void AppendPrimitiveValue(object valueToAppend, int dept)
        {
            sb.Append("\"" + valueToAppend.ToString() + "\"");
        }

        public void End(string objName)
        {
            if (!_isTopObjectList)
            {
                sb.AppendLine();
                sb.Append("}");
            }
        }

        public string GetString()
        {
            return sb.ToString();
        }

        public void AppendNullValue(string name, int dept, bool inList)
        {
            WriteIndentation();

            if (inList)
            {
                sb.AppendLine("null,");
            }
            else
            {
                sb.AppendLine("\"" + name + "\" : null,");
            }
        }

    }
}


